package com.icee.myth.server;

import com.icee.myth.common.AbstractHeartbeatServer;
import com.icee.myth.common.channelContext.HeartbeatChannelContext;
import com.icee.myth.common.message.serverMessage.*;
import com.icee.myth.common.message.serverMessage.builder.MessageBuilder;
import com.icee.myth.log.GameLogger;
import com.icee.myth.log.message.FileDebugGameLogMessage;
import com.icee.myth.log.message.builder.GameLogMessageBuilder;
import com.icee.myth.protobuf.builder.ManagerToServerBuilder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.util.concurrent.LinkedTransferQueue;


/**
 * 对manager的服务，此服务用于与Manager Server交互
 * @author liuxianke
 */
public class ManagerConnectServer extends AbstractHeartbeatServer {

    //Singleton
    public static ManagerConnectServer INSTANCE = new ManagerConnectServer();

    //getInstance操作的第一次调用在Main的start中，因此无需同步
//    public static ManagerConnectServer INSTANCE {
//        return INSTANCE;
//    }

    private ManagerConnectServer() {
    }

    @Override
    public void init(String host, int totalClientNum, int port, ChannelHandler childHandler, LinkedTransferQueue<Message> queue) {
        this.queue = queue;
        this.host = host;
        this.port = port;
        this.totalClientNum = totalClientNum;

        channelContexts = new HeartbeatChannelContext[totalClientNum];
        for (int i = 0; i < totalClientNum; i++) {
            channelContexts[i] = new HeartbeatChannelContext();
        }

        // Start server with Nb of active threads = 2*NB CPU + 1 as maximum.
        final int workerCount = Runtime.getRuntime().availableProcessors() * 2 + 1;

        bossGroup = new NioEventLoopGroup();
        workGroup = new NioEventLoopGroup(workerCount);

        // Configure the server.
        bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup);
        bootstrap.channel(NioServerSocketChannel.class);

        bootstrap.option(ChannelOption.TCP_NODELAY, true);    // 无延迟
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);    // 保持存活
        bootstrap.option(ChannelOption.SO_REUSEADDR, true);    // 重复利用地址

        bootstrap.childHandler(childHandler);
    }

    @Override
    protected Object buildServerHeartBeat() {
        return ManagerToServerBuilder.buildServerHeartbeat();  // TODO: 用静态对象
    }

    @Override
    protected Message buildClientDownMessage(int clientId) {
        return MessageBuilder.buildManagerDownMessage();
    }

    @Override
    protected void clientDownWarning(int clientId) {
        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                "Manager is down!"));
    }

    @Override
    protected void clientCloseWarning(int clientId) {
        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                "Manager is closed!"));
    }

    public void handleMessage(Message message) {
        switch (message.getType()) {
            case ALL_HEARTBEAT: {
                heartbeat();    // 向连接方发心跳
                break;
            }
            case ALL_MANAGERHEARTBEAT: {
                // 对方有心跳，重置心跳计数
                restoreHeartbeat(0);
                break;
            }
            case ALL_MANAGERCONNECT: {
                // 处理LGW Connect消息
                if(channelContexts[0].isActive()) {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Manager muti-connected!"));
                    // TODO: 是否要产生重复连接消息到MessageQueue
                }
                addClient(0, ((InternalChannelMessage)message).channel);
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_INFO,
                        "Manager connected!"));
                break;
            }
            case ALL_MANAGERCLOSE: {
                // 处理LGW Close消息
                clientClose(((InternalChannelMessage)message).channel);
                break;
            }
            case ALL_CALCULATE_WIN_RATE_RESULT: {
                if(channelContexts[0].isActive()) {
                    CalculateWinRateBattleResultMessage calculateWinRateBattleResultMessage = (CalculateWinRateBattleResultMessage) message;
                    channelContexts[0].fastWrite(ManagerToServerBuilder.buildBattleWinRateResult(calculateWinRateBattleResultMessage.winNum, calculateWinRateBattleResultMessage.lostNum, calculateWinRateBattleResultMessage.drawNum));
                }
                break;
            }
            case ALL_CALCULATE_CARD_DRAW_RATE_RESULT: {
                if(channelContexts[0].isActive()) {
                    CalculateCardDrawRateResultMessage calculateCardDrawRateResultMessage = (CalculateCardDrawRateResultMessage) message;
                    channelContexts[0].fastWrite(ManagerToServerBuilder.buildCardDrawRateResult(calculateCardDrawRateResultMessage.result));
                }
                break;
            }
            case ALL_UNINIT_OCCUPY_INFO_MESSAGE: {
                if(channelContexts[0].isActive()) {
                    UninitOccupyInfoMessage uninitOccupyInfoMessage = (UninitOccupyInfoMessage) message;
                    channelContexts[0].fastWrite(ManagerToServerBuilder.buildUnintOccupyInfo(uninitOccupyInfoMessage.result));
                }
                break;
            }
            case ALL_FIGHTING_OCCUPY_INFO_MESSAGE: {
                if(channelContexts[0].isActive()) {
                    FightingOccupyInfoMessage fightingOccupyInfoMessage = (FightingOccupyInfoMessage) message;
                    channelContexts[0].fastWrite(ManagerToServerBuilder.buildFightingOccupyInfo(fightingOccupyInfoMessage.result));
                }
                break;
            }
        }
    }
}
